﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using MVVM_CAD.Model;

namespace MVVM_CAD.Algorithms
{
    public class BressenhamLine
    {
        public static IEnumerable<IPoint> GetLineRepresentation(IPoint begin, IPoint end)
        {
            var x0 = (int)begin.X;
            var y0 = (int)begin.Y;
            var x1 = (int)end.X;
            var y1 = (int)end.Y;
            var steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
            if (steep)
            {
                Swap(ref x0, ref y0);
                Swap(ref x1, ref y1);
                yield return new CustomPoint(y0, x0);
            }
            var deltax = Math.Abs(x1 - x0);
            var deltay = Math.Abs(y1 - y0);
            var error = 0;
            var x = x0;
            var y = y0;
            int xstep, ystep;
            if (x0 < x1)
                xstep = 1;
            else
                xstep = -1;
            if (y0 < y1)
                ystep = 1;
            else
                ystep = -1;
            while (x != x1)
            {
                x += xstep;
                error += deltay;
                if ((error) > deltax)
                {
                    y += ystep;
                    error -= deltax;
                }
                if (steep)
                {
                    yield return new CustomPoint(y, x);
                }
                else
                {
                    yield return new CustomPoint(x, y);
                }
            }
        }

        private static void Swap(ref int a, ref int b)
        {
            var tmp = a;
            a = b;
            b = tmp;
        }

        private static double Round2(double Number)
        {
            var NumDigitsAfterDecimal = 0;
            if (Number - Math.Round(Number, NumDigitsAfterDecimal) >= 0.5 / (10 ^ NumDigitsAfterDecimal))
                return Math.Round(Number, NumDigitsAfterDecimal) + 0.1 / (10 ^ NumDigitsAfterDecimal);
            return Math.Round(Number, NumDigitsAfterDecimal);
        }

        private static int RoundClose(double Number)
        {
            if (Number == Round2(Number))
                return (int) Number;
            if (Number - Round2(Number) > 0)
                return (int) Round2(Number);
            return (int) (Round2(Number) - 1);
        }

        public static IEnumerable<IPoint> DrawAntiAliasPixel(double x , double y ,int  r ,int g,int b)
        {
            int cX = RoundClose(x);
            int cY = RoundClose(y);

            int dX = (int) (x - cX);
            int dY = (int) (y - cY);
            int dX2 = 1 - dX;
            int dY2 = 1 - dY;
            Color BGColor = Colors.Black;
            int BGRed = BGColor.R;
            int BGGreen = BGColor.G;
            int BGBlue = BGColor.B;

            double Percent = dX2*dY2;
            double InvPercent = 1 - Percent;

            byte NewRed = (byte) (Percent*r + InvPercent*BGRed);
            byte NewGreen = (byte) (Percent*g + InvPercent*BGGreen);
            byte NewBlue = (byte) (Percent*b + InvPercent*BGBlue);

            yield return new CustomPoint(cX, cY, Color.FromRgb(NewRed, NewGreen, NewBlue));
            
            BGRed = BGColor.R;
            BGGreen = BGColor.G;
            BGBlue = BGColor.B;

            Percent = dX*dY2;
            InvPercent = 1 - Percent;

            NewRed = (byte) (Percent*r + InvPercent*BGRed);
            NewGreen = (byte) (Percent*g + InvPercent*BGGreen);
            NewBlue = (byte) (Percent*b + InvPercent*BGBlue);

            yield return new CustomPoint(cX + 1, cY, Color.FromRgb(NewRed, NewGreen, NewBlue));
            
            BGRed = BGColor.R;
            BGGreen = BGColor.G;
            BGBlue = BGColor.B;

            Percent = dX2*dY;
            InvPercent = 1 - Percent;

            NewRed = (byte) (Percent*r + InvPercent*BGRed);
            NewGreen = (byte) (Percent*g + InvPercent*BGGreen);
            NewBlue = (byte) (Percent*b + InvPercent*BGBlue);

            yield return new CustomPoint(cX, cY + 1, Color.FromRgb(NewRed, NewGreen, NewBlue));

            BGRed = BGColor.R;
            BGGreen = BGColor.G;
            BGBlue = BGColor.B;

            Percent = dX*dY;
            InvPercent = 1 - Percent;

            NewRed = (byte) (Percent*r + InvPercent*BGRed);
            NewGreen = (byte) (Percent*g + InvPercent*BGGreen);
            NewBlue = (byte) (Percent*b + InvPercent*BGBlue);

            yield return new CustomPoint(cX, cY + 1, Color.FromRgb(NewRed, NewGreen, NewBlue));
        }
    }
}
